/*
    SUSAN® - Sole of Unix Save ANything

   Copyright (C) 2013-2014 Skyatlas Co. CN
   

   
*/
/*
 * Marco van Wieringen, December 2013
 */
/**
 * @file
 * This file contains the HTABLE abstraction of the accurate payload storage.
 */

#include "include/susan.h"
#include "filed/filed.h"
#include "accurate.h"
#include "lib/attribs.h"

namespace filedaemon {

static int debuglevel = 100;

SusanAccurateFilelistHtable::SusanAccurateFilelistHtable(
    JobControlRecord* jcr,
    uint32_t number_of_files)
{
  jcr_ = jcr;
  filenr_ = 0;
  number_of_previous_files_ = number_of_files;

  CurFile* elt = NULL;
  file_list_ = (htable*)malloc(sizeof(htable));
  file_list_->init(elt, &elt->link, number_of_previous_files_);
  seen_bitmap_ = (char*)malloc(NbytesForBits(number_of_previous_files_));
  ClearAllBits(number_of_previous_files_, seen_bitmap_);
}

bool SusanAccurateFilelistHtable::AddFile(char* fname,
                                           int fname_length,
                                           char* lstat,
                                           int lstat_length,
                                           char* chksum,
                                           int chksum_length,
                                           int32_t delta_seq)
{
  CurFile* item;
  int total_length;
  bool retval = true;

  total_length =
      sizeof(CurFile) + fname_length + lstat_length + chksum_length + 3;
  item = (CurFile*)file_list_->hash_malloc(total_length);

  item->fname = (char*)item + sizeof(CurFile);
  memcpy(item->fname, fname, fname_length);
  item->fname[fname_length] = '\0';

  item->payload.lstat = item->fname + fname_length + 1;
  memcpy(item->payload.lstat, lstat, lstat_length);
  item->payload.lstat[lstat_length] = '\0';

  item->payload.chksum = item->payload.lstat + lstat_length + 1;
  if (chksum_length) { memcpy(item->payload.chksum, chksum, chksum_length); }
  item->payload.chksum[chksum_length] = '\0';

  item->payload.delta_seq = delta_seq;
  item->payload.filenr = filenr_++;
  file_list_->insert(item->fname, item);

  if (chksum) {
    Dmsg4(debuglevel, "add fname=<%s> lstat=%s delta_seq=%i chksum=%s\n", fname,
          lstat, delta_seq, chksum);
  } else {
    Dmsg2(debuglevel, "add fname=<%s> lstat=%s\n", fname, lstat);
  }

  return retval;
}

bool SusanAccurateFilelistHtable::EndLoad()
{
  /*
   * Nothing to do.
   */
  return true;
}

accurate_payload* SusanAccurateFilelistHtable::lookup_payload(char* fname)
{
  CurFile* temp;

  temp = (CurFile*)file_list_->lookup(fname);
  return (temp) ? &temp->payload : NULL;
}

bool SusanAccurateFilelistHtable::UpdatePayload(char* fname,
                                                 accurate_payload* payload)
{
  /*
   * Nothing to do.
   */
  return true;
}

bool SusanAccurateFilelistHtable::SendBaseFileList()
{
  CurFile* elt;
  FindFilesPacket* ff_pkt;
  int32_t LinkFIc;
  struct stat statp;
  int stream = STREAM_UNIX_ATTRIBUTES;

  if (!jcr_->accurate || jcr_->getJobLevel() != L_FULL) { return true; }

  if (file_list_ == NULL) { return true; }

  ff_pkt = init_find_files();
  ff_pkt->type = FT_BASE;

  foreach_htable (elt, file_list_) {
    if (BitIsSet(elt->payload.filenr, seen_bitmap_)) {
      Dmsg1(debuglevel, "base file fname=%s\n", elt->fname);
      DecodeStat(elt->payload.lstat, &statp, sizeof(statp),
                 &LinkFIc); /* decode catalog stat */
      ff_pkt->fname = elt->fname;
      ff_pkt->statp = statp;
      EncodeAndSendAttributes(jcr_, ff_pkt, stream);
    }
  }

  TermFindFiles(ff_pkt);
  return true;
}

bool SusanAccurateFilelistHtable::SendDeletedList()
{
  CurFile* elt;
  FindFilesPacket* ff_pkt;
  int32_t LinkFIc;
  struct stat statp;
  int stream = STREAM_UNIX_ATTRIBUTES;

  if (!jcr_->accurate) { return true; }

  ff_pkt = init_find_files();
  ff_pkt->type = FT_DELETED;

  foreach_htable (elt, file_list_) {
    if (BitIsSet(elt->payload.filenr, seen_bitmap_) ||
        PluginCheckFile(jcr_, elt->fname)) {
      continue;
    }
    Dmsg1(debuglevel, "deleted fname=%s\n", elt->fname);
    ff_pkt->fname = elt->fname;
    DecodeStat(elt->payload.lstat, &statp, sizeof(statp),
               &LinkFIc); /* decode catalog stat */
    ff_pkt->statp.st_mtime = statp.st_mtime;
    ff_pkt->statp.st_ctime = statp.st_ctime;
    EncodeAndSendAttributes(jcr_, ff_pkt, stream);
  }

  TermFindFiles(ff_pkt);
  return true;
}

void SusanAccurateFilelistHtable::destroy()
{
  if (file_list_) {
    file_list_->destroy();
    free(file_list_);
    file_list_ = NULL;
  }

  if (seen_bitmap_) {
    free(seen_bitmap_);
    seen_bitmap_ = NULL;
  }

  filenr_ = 0;
}

} /* namespace filedaemon */
